1   /*
2    * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.awt.motif;
27  
28  import java.awt.Font;
29  import java.io.BufferedReader;
30  import java.io.File;
31  import java.io.FileInputStream;
32  import java.io.InputStreamReader;
33  import java.nio.charset.Charset;
34  import java.util.HashMap;
35  import java.util.HashSet;
36  import java.util.Locale;
37  import java.util.Properties;
38  import java.util.Scanner;
39  import sun.awt.FontConfiguration;
40  import sun.awt.X11FontManager;
41  import sun.awt.X11GraphicsEnvironment;
42  import sun.font.FontManager;
43  import sun.font.SunFontManager;
44  import sun.font.FontManagerFactory;
45  import sun.font.FontUtilities;
46  import sun.java2d.SunGraphicsEnvironment;
47  import sun.util.logging.PlatformLogger;
48  
49  public class MFontConfiguration extends FontConfiguration {
50  
51      private static FontConfiguration fontConfig = null;
52      private static PlatformLogger logger;
53  
54      public MFontConfiguration(SunFontManager fm) {
55          super(fm);
56          if (FontUtilities.debugFonts()) {
57              logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");
58          }
59          initTables();
60      }
61  
62  
63      public MFontConfiguration(SunFontManager fm,
64                                boolean preferLocaleFonts,
65                                boolean preferPropFonts) {
66          super(fm, preferLocaleFonts, preferPropFonts);
67          if (FontUtilities.debugFonts()) {
68              logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");
69          }
70          initTables();
71      }
72  
73      /* Needs to be kept in sync with updates in the languages used in
74       * the fontconfig files.
75       */
76      protected void initReorderMap() {
77          reorderMap = new HashMap();
78          if (osName == null) {  /* null means SunOS */
79              initReorderMapForSolaris();
80          } else {
81              initReorderMapForLinux();
82          }
83      }
84  
85      private void initReorderMapForSolaris() {
86          /* Don't create a no-op entry, so we can optimize this case
87           * i.e. we don't need to do anything so can avoid slower paths in
88           * the code.
89           */
90  //      reorderMap.put("UTF-8", "latin-1");
91          reorderMap.put("UTF-8.hi", "devanagari"); // NB is in Lucida.
92          reorderMap.put("UTF-8.ja",
93                         split("japanese-x0201,japanese-x0208,japanese-x0212"));
94          reorderMap.put("UTF-8.ko", "korean-johab");
95          reorderMap.put("UTF-8.th", "thai");
96          reorderMap.put("UTF-8.zh.TW", "chinese-big5");
97          reorderMap.put("UTF-8.zh.HK", split("chinese-big5,chinese-hkscs"));
98          if (FontUtilities.isSolaris8) {
99              reorderMap.put("UTF-8.zh.CN", split("chinese-gb2312,chinese-big5"));
100         } else {
101             reorderMap.put("UTF-8.zh.CN",
102                            split("chinese-gb18030-0,chinese-gb18030-1"));
103         }
104         reorderMap.put("UTF-8.zh",
105                        split("chinese-big5,chinese-hkscs,chinese-gb18030-0,chinese-gb18030-1"));
106         reorderMap.put("Big5", "chinese-big5");
107         reorderMap.put("Big5-HKSCS", split("chinese-big5,chinese-hkscs"));
108         if (! FontUtilities.isSolaris8 && ! FontUtilities.isSolaris9) {
109             reorderMap.put("GB2312", split("chinese-gbk,chinese-gb2312"));
110         } else {
111             reorderMap.put("GB2312","chinese-gb2312");
112         }
113         reorderMap.put("x-EUC-TW",
114             split("chinese-cns11643-1,chinese-cns11643-2,chinese-cns11643-3"));
115         reorderMap.put("GBK", "chinese-gbk");
116         reorderMap.put("GB18030",split("chinese-gb18030-0,chinese-gb18030-1"));
117 
118         reorderMap.put("TIS-620", "thai");
119         reorderMap.put("x-PCK",
120                        split("japanese-x0201,japanese-x0208,japanese-x0212"));
121         reorderMap.put("x-eucJP-Open",
122                        split("japanese-x0201,japanese-x0208,japanese-x0212"));
123         reorderMap.put("EUC-KR", "korean");
124         /* Don't create a no-op entry, so we can optimize this case */
125 //      reorderMap.put("ISO-8859-1", "latin-1");
126         reorderMap.put("ISO-8859-2", "latin-2");
127         reorderMap.put("ISO-8859-5", "cyrillic-iso8859-5");
128         reorderMap.put("windows-1251", "cyrillic-cp1251");
129         reorderMap.put("KOI8-R", "cyrillic-koi8-r");
130         reorderMap.put("ISO-8859-6", "arabic");
131         reorderMap.put("ISO-8859-7", "greek");
132         reorderMap.put("ISO-8859-8", "hebrew");
133         reorderMap.put("ISO-8859-9", "latin-5");
134         reorderMap.put("ISO-8859-13", "latin-7");
135         reorderMap.put("ISO-8859-15", "latin-9");
136     }
137 
138     private void initReorderMapForLinux() {
139         reorderMap.put("UTF-8.ja.JP", "japanese-iso10646");
140         reorderMap.put("UTF-8.ko.KR", "korean-iso10646");
141         reorderMap.put("UTF-8.zh.TW", "chinese-tw-iso10646");
142         reorderMap.put("UTF-8.zh.HK", "chinese-tw-iso10646");
143         reorderMap.put("UTF-8.zh.CN", "chinese-cn-iso10646");
144         reorderMap.put("x-euc-jp-linux",
145                         split("japanese-x0201,japanese-x0208"));
146         reorderMap.put("GB2312", "chinese-gb18030");
147         reorderMap.put("Big5", "chinese-big5");
148         reorderMap.put("EUC-KR", "korean");
149         if (osName.equals("Sun")){
150             reorderMap.put("GB18030", "chinese-cn-iso10646");
151         }
152         else {
153             reorderMap.put("GB18030", "chinese-gb18030");
154         }
155     }
156 
157     /**
158      * Sets the OS name and version from environment information.
159      */
160     protected void setOsNameAndVersion(){
161         super.setOsNameAndVersion();
162 
163         if (osName.equals("SunOS")) {
164             //don't care os name on Solaris
165             osName = null;
166         } else if (osName.equals("Linux")) {
167             try {
168                 File f;
169                 if ((f = new File("/etc/fedora-release")).canRead()) {
170                     osName = "Fedora";
171                     osVersion = getVersionString(f);
172                 } else if ((f = new File("/etc/redhat-release")).canRead()) {
173                     osName = "RedHat";
174                     osVersion = getVersionString(f);
175                 } else if ((f = new File("/etc/turbolinux-release")).canRead()) {
176                     osName = "Turbo";
177                     osVersion = getVersionString(f);
178                 } else if ((f = new File("/etc/SuSE-release")).canRead()) {
179                     osName = "SuSE";
180                     osVersion = getVersionString(f);
181                 } else if ((f = new File("/etc/lsb-release")).canRead()) {
182                     /* Ubuntu and (perhaps others) use only lsb-release.
183                      * Syntax and encoding is compatible with java properties.
184                      * For Ubuntu the ID is "Ubuntu".
185                      */
186                     Properties props = new Properties();
187                     props.load(new FileInputStream(f));
188                     osName = props.getProperty("DISTRIB_ID");
189                     osVersion =  props.getProperty("DISTRIB_RELEASE");
190                 }
191             } catch (Exception e) {
192             }
193         }
194         return;
195     }
196 
197     /**
198      * Gets the OS version string from a Linux release-specific file.
199      */
200     private String getVersionString(File f){
201         try {
202             Scanner sc  = new Scanner(f);
203             return sc.findInLine("(\\d)+((\\.)(\\d)+)*");
204         }
205         catch (Exception e){
206         }
207         return null;
208     }
209 
210     private static final String fontsDirPrefix = "$JRE_LIB_FONTS";
211 
212     protected String mapFileName(String fileName) {
213         if (fileName != null && fileName.startsWith(fontsDirPrefix)) {
214             return SunFontManager.jreFontDirName
215                     + fileName.substring(fontsDirPrefix.length());
216         }
217         return fileName;
218     }
219 
220     // overrides FontConfiguration.getFallbackFamilyName
221     public String getFallbackFamilyName(String fontName, String defaultFallback) {
222         // maintain compatibility with old font.properties files, which
223         // either had aliases for TimesRoman & Co. or defined mappings for them.
224         String compatibilityName = getCompatibilityFamilyName(fontName);
225         if (compatibilityName != null) {
226             return compatibilityName;
227         }
228         return defaultFallback;
229     }
230 
231     protected String getEncoding(String awtFontName,
232             String characterSubsetName) {
233         // extract encoding field from XLFD
234         int beginIndex = 0;
235         int fieldNum = 13; // charset registry field
236         while (fieldNum-- > 0 && beginIndex >= 0) {
237             beginIndex = awtFontName.indexOf("-", beginIndex) + 1;
238         }
239         if (beginIndex == -1) {
240             return "default";
241         }
242         String xlfdEncoding = awtFontName.substring(beginIndex);
243         if (xlfdEncoding.indexOf("fontspecific") > 0) {
244             if (awtFontName.indexOf("dingbats") > 0) {
245                 return "sun.awt.motif.X11Dingbats";
246             } else if (awtFontName.indexOf("symbol") > 0) {
247                 return "sun.awt.Symbol";
248             }
249         }
250         String encoding = (String) encodingMap.get(xlfdEncoding);
251         if (encoding == null) {
252             encoding = "default";
253         }
254         return encoding;
255     }
256 
257     protected Charset getDefaultFontCharset(String fontName) {
258         return Charset.forName("ISO8859_1");
259     }
260 
261     /* methods for Motif support *********************************************/
262 
263     private String[][] motifFontSets = new String[NUM_FONTS][NUM_STYLES];
264 
265     public String getMotifFontSet(String fontName, int style) {
266         assert isLogicalFontFamilyName(fontName);
267         fontName = fontName.toLowerCase(Locale.ENGLISH);
268         int fontIndex = getFontIndex(fontName);
269         int styleIndex = getStyleIndex(style);
270         return getMotifFontSet(fontIndex, styleIndex);
271     }
272 
273     private String getMotifFontSet(int fontIndex, int styleIndex) {
274         String fontSet = motifFontSets[fontIndex][styleIndex];
275         if (fontSet == null) {
276             fontSet = buildMotifFontSet(fontIndex, styleIndex);
277             motifFontSets[fontIndex][styleIndex] = fontSet;
278         }
279         return fontSet;
280     }
281 
282     private String buildMotifFontSet(int fontIndex, int styleIndex) {
283         StringBuilder buffer = new StringBuilder();
284         short[] scripts = getCoreScripts(fontIndex);
285         for (int i = 0; i < scripts.length; i++) {
286             short nameID = getComponentFontIDMotif(scripts[i], fontIndex, styleIndex);
287             if (nameID == 0) {
288                 nameID = getComponentFontID(scripts[i], fontIndex, styleIndex);
289             }
290             String name = getComponentFontName(nameID);
291             if (name == null || name.endsWith("fontspecific")) {
292                 continue;
293             }
294             if (buffer.length() > 0) {
295                 buffer.append(',');
296             }
297             buffer.append(name);
298         }
299         return buffer.toString();
300     }
301 
302     protected String getFaceNameFromComponentFontName(String componentFontName) {
303         return null;
304     }
305 
306     protected String getFileNameFromComponentFontName(String componentFontName) {
307         // for X11, component font name is XLFD
308         // if we have a file name already, just use it; otherwise let's see
309         // what the graphics environment can provide
310         String fileName = getFileNameFromPlatformName(componentFontName);
311         if (fileName != null && fileName.charAt(0) == '/' &&
312             !needToSearchForFile(fileName)) {
313             return fileName;
314         }
315         return ((X11FontManager) fontManager).getFileNameFromXLFD(componentFontName);
316     }
317 
318     /**
319      * Get default font for Motif widgets to use, preventing them from
320      * wasting time accessing inappropriate X resources.  This is called
321      * only from native code.
322      *
323      * This is part of a Motif specific performance enhancement.  By
324      * default, when Motif widgets are created and initialized, Motif will
325      * set up default fonts for the widgets, which we ALWAYS override.
326      * This set up includes finding the default font in the widget's X
327      * resources and fairly expensive requests of the X server to identify
328      * the specific font or fontset.  We avoid all of this overhead by
329      * providing a well known font to use at the creation of widgets, where
330      * possible.
331      *
332      * The X11 fonts are specified by XLFD strings which have %d as a
333      * marker to indicate where the fontsize should be substituted.  [The
334      * libc function sprintf() is used to replace it.]  The value 140
335      * specifies a font size of 14 points.
336      */
337     private static String getDefaultMotifFontSet() {
338         String font = ((MFontConfiguration) getFontConfiguration()).getMotifFontSet("sansserif", Font.PLAIN);
339         if (font != null) {
340             int i;
341             while ((i = font.indexOf("%d")) >= 0) {
342                 font = font.substring(0, i) + "140" + font.substring(i+2);
343             }
344         }
345         return font;
346     }
347 
348     public HashSet<String> getAWTFontPathSet() {
349         HashSet<String> fontDirs = new HashSet<String>();
350         short[] scripts = getCoreScripts(0);
351         for (int i = 0; i< scripts.length; i++) {
352             String path = getString(table_awtfontpaths[scripts[i]]);
353             if (path != null) {
354                 int start = 0;
355                 int colon = path.indexOf(':');
356                 while (colon >= 0) {
357                     fontDirs.add(path.substring(start, colon));
358                     start = colon + 1;
359                     colon = path.indexOf(':', start);
360                 }
361                 fontDirs.add((start == 0) ? path : path.substring(start));
362             }
363         }
364         return fontDirs;
365     }
366 
367     /* methods for table setup ***********************************************/
368 
369     private static HashMap encodingMap = new HashMap();
370 
371     private void initTables() {
372         // encodingMap maps XLFD encoding component to
373         // name of corresponding java.nio charset
374         encodingMap.put("iso8859-1", "ISO-8859-1");
375         encodingMap.put("iso8859-2", "ISO-8859-2");
376         encodingMap.put("iso8859-4", "ISO-8859-4");
377         encodingMap.put("iso8859-5", "ISO-8859-5");
378         encodingMap.put("iso8859-6", "ISO-8859-6");
379         encodingMap.put("iso8859-7", "ISO-8859-7");
380         encodingMap.put("iso8859-8", "ISO-8859-8");
381         encodingMap.put("iso8859-9", "ISO-8859-9");
382         encodingMap.put("iso8859-13", "ISO-8859-13");
383         encodingMap.put("iso8859-15", "ISO-8859-15");
384         encodingMap.put("gb2312.1980-0", "sun.awt.motif.X11GB2312");
385         if (osName == null) {
386             // use standard converter on Solaris
387             encodingMap.put("gbk-0", "GBK");
388         } else {
389             encodingMap.put("gbk-0", "sun.awt.motif.X11GBK");
390         }
391         encodingMap.put("gb18030.2000-0", "sun.awt.motif.X11GB18030_0");
392         encodingMap.put("gb18030.2000-1", "sun.awt.motif.X11GB18030_1");
393         encodingMap.put("cns11643-1", "sun.awt.motif.X11CNS11643P1");
394         encodingMap.put("cns11643-2", "sun.awt.motif.X11CNS11643P2");
395         encodingMap.put("cns11643-3", "sun.awt.motif.X11CNS11643P3");
396         encodingMap.put("big5-1", "Big5");
397         encodingMap.put("big5-0", "Big5");
398         encodingMap.put("hkscs-1", "Big5-HKSCS");
399         encodingMap.put("ansi-1251", "windows-1251");
400         encodingMap.put("koi8-r", "KOI8-R");
401         encodingMap.put("jisx0201.1976-0", "sun.awt.motif.X11JIS0201");
402         encodingMap.put("jisx0208.1983-0", "sun.awt.motif.X11JIS0208");
403         encodingMap.put("jisx0212.1990-0", "sun.awt.motif.X11JIS0212");
404         encodingMap.put("ksc5601.1987-0", "sun.awt.motif.X11KSC5601");
405         encodingMap.put("ksc5601.1992-3", "sun.awt.motif.X11Johab");
406         encodingMap.put("tis620.2533-0", "TIS-620");
407         encodingMap.put("iso10646-1", "UTF-16BE");
408     }
409 
410 }